{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [Object对象简介](https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247484210&idx=1&sn=9d40e2e4c72f0727c7b7925cbe314fc0&chksm=ebd74233dca0cb2560677c7dc7746bf166195d793860c41ab477431af2cf0a6004477e27b814&scene=21###wechat_redirect)\n",
    "> 声明：本文都是使用JDK1.8\n",
    "\n",
    "Java中出现什么，都可以认为它是对象(**除了**八大基本数据类型。当然了，八大基本数据类型也能**装箱**成为对象)：\n",
    "\n",
    "- 而Object就是这些对象的最高级别的，所有的Java对象都**隐式**地继承了Object对象(不用显示写extends继承)\n",
    "- 所有的Java对象都**拥有Object默认的方法。**\n",
    "\n",
    "Object对象的方法可以归纳成这几个：\n",
    "\n",
    "－ `registerNatives()`//底层实现、不研究\n",
    "- `hashCode()`\n",
    "- `equals(Object obj)`\n",
    "- `clone()`\n",
    "- `toString()`\n",
    "- `notify()`\n",
    "- `notifyAll()`\n",
    "- `wait(long timeout)`//还有重载了两个\n",
    "- `finalize()`\n",
    "\n",
    "Object一共有`11`个方法，其中一个为底层的实现`registerNatives()`，其中两个`wait()`和`wait(long timeout, int nanos)`重载方法。\n",
    "\n",
    "- 所以我们真正需要看的就是`8个`方法\n",
    "还有`一个属性`：`public final native Class<?> getClass();`，返回字节码文件对象(@code Object)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# equals和hashCode方法\n",
    "equals和hashCode方法可以说是面试的重点题了，配合着String可以说在面试题中**哪都有它们的存在**。\n",
    "\n",
    "首先，我们来看看equals和hashCode在Object中**原生**的实现吧：\n",
    "\n",
    "hashCode：\n",
    "```java\n",
    "public native int hashCode();\n",
    "```\n",
    "equals:\n",
    "```java\n",
    "public boolean equals(Object obj){\n",
    "    return(this == obj);\n",
    "}\n",
    "```\n",
    "看上去都非常简单：\n",
    "\n",
    "- hashCode()由native方法底层实现了。\n",
    "- equals()就直接==判断是否相等了。\n",
    "想要更加清晰它们究竟是做什么的，我们来读读它的注释：\n",
    "\n",
    "hashCode()\n",
    "1. 返回对象的一个hash值，对于是散列表结构的对象(比如HashMap)是有好处的\n",
    "2. 同一个对象调用的hashCode方法，返回的int应该是一致的！(如果该对象没有被修改)\n",
    "3. 如果两个对象equals()不相等，hashCode()可以不相等。但是程序员发现，如果两个对象不相等，那么hashCode也不相等的话，这会提高散列表性能\n",
    "4. hashCode默认是由对象的地址转换而来的，也是根据不同的对象转换成不同的哈希值（但这种实现不是Java语言要求的，所以常常重写它）\n",
    "\n",
    "equals()\n",
    "1. 判断该对象是否与指定的对象相等\n",
    "2. 自反性\n",
    "3. 对称性\n",
    "4. 传递性\n",
    "5. 一致性\n",
    "6. 传入的参数为null，应该返回的是false\n",
    "7. 默认的实现是：只有这两个对象的地址相等（==），那才认为这两个对象相等（返回true）\n",
    "8. 无论何时重写equals()方法，都要重写hashCode的方法(以维持hashCode的约定)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "根据注释我们可以**总结以下的要点：**\n",
    "\n",
    "- 重写`equals()`方法，就必须重写`hashCode()`的方法\n",
    "- `equals()`方法默认是比较对象的地址，使用的是`==`等值运算符\n",
    "- `hashCode()`方法对底层是散列表的对象有提升性能的功能\n",
    "- 同一个对象(如果该对象没有被修改)：那么重复调用`hashCode()`那么返回的int是相同的！\n",
    "- `hashCode()`方法默认是由对象的地址转换而来的\n",
    "- `equals()`方法还有5个默认的原则：\n",
    "    - 自反性--->调用`equals()`返回的是true，无论这两个对象谁调用`equals()`都好，返回的都是true\n",
    "    - 一致性--->只要对象没有被修改，那么多次调用还是返回对应的结果！\n",
    "    - 传递性--->`x.equals(y)`和`y.equals(z)`都返回true，那么可以得出：`x.equals(z)`返回true\n",
    "    - 对称性--->`x.equals(y)`和`y.equals(x)`结果应该是相等的。\n",
    "    - 传入的参数为null，返回的是false\n",
    "为啥说`hashCode()`以散列表为底层带来性能的提升是很容易理解的。如果hash值都不相等，那么可以直接判断该key是不相等的了！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## equals和hashCode方法重写\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T14:58+0000",
     "start_time": "2020-08-25T14:58:36.800Z"
    }
   },
   "outputs": [
    {
     "ename": "CompilationException",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30mpublic boolean \u001b[0m\u001b[1m\u001b[30m\u001b[41mequals\u001b[0m\u001b[1m\u001b[30m(Object obj){\u001b[0m",
      "\u001b[1m\u001b[31mJShell method names must not match Object methods: getClass wait hashCode equals notifyAll toString notify\u001b[0m",
      ""
     ]
    }
   ],
   "source": [
    "/**\n",
    "*使用IDEA默认的模板生成的equals()和hashCode()\n",
    "*/\n",
    "@Override\n",
    "public boolean equals(Object obj){\n",
    "    if(this == obj) return true; //优化操作\n",
    "    if(!(obj instanceof Address)) return false; //这里默认判断的是instanceof也好(也能判断getClass),看需求了\n",
    "    \n",
    "    Address address = (Address) obj;\n",
    "    \n",
    "    /**\n",
    "    *只要他们相等，那么就返回true\n",
    "    */\n",
    "    if(provinceNo != address.provinceNo) return false;\n",
    "    if(cityNo != address.cityNo) return false;\n",
    "    return streetNo == address.streetNo;\n",
    "}\n",
    "\n",
    "@Override\n",
    "public int hashNode(){\n",
    "    int result = provinceNo;\n",
    "    result = 31 * result + cityNo; //重写了equals()就要重写hashCode(),这是hashCode的规范\n",
    "    result = 31 * result + streetNo; //31哈希值尽可能不一样\n",
    "    return result;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## String实现的equals和hashCode方法\n",
    "我们在初学的时候可能就听过了：String已经实现了equals和hashCode方法了。\n",
    "\n",
    "这也就是为什么，我们可以直接使用String.equals()来**判断两个字符串**是否相等！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T15:06+0000",
     "start_time": "2020-08-25T15:06:13.449Z"
    }
   },
   "outputs": [
    {
     "ename": "CompilationException",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m    if(\u001b[0m\u001b[1m\u001b[30m\u001b[41mthis\u001b[0m\u001b[1m\u001b[30m == obj){ //优化，地址相等就一定相等\u001b[0m",
      "\u001b[1m\u001b[31mnon-static variable this cannot be referenced from a static context\u001b[0m",
      "",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        int n = \u001b[0m\u001b[1m\u001b[30m\u001b[41mvalue\u001b[0m\u001b[1m\u001b[30m.length;\u001b[0m",
      "\u001b[1m\u001b[31mcannot find symbol\u001b[0m",
      "\u001b[1m\u001b[31m  symbol:   variable value\u001b[0m",
      "",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m        if(n == \u001b[0m\u001b[1m\u001b[30m\u001b[41mstring.value\u001b[0m\u001b[1m\u001b[30m.length){\u001b[0m",
      "\u001b[1m\u001b[31mvalue has private access in java.lang.String\u001b[0m",
      "",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m            char ch1[] = \u001b[0m\u001b[1m\u001b[30m\u001b[41mvalue\u001b[0m\u001b[1m\u001b[30m;\u001b[0m",
      "\u001b[1m\u001b[31mcannot find symbol\u001b[0m",
      "\u001b[1m\u001b[31m  symbol:   variable value\u001b[0m",
      "",
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30m            char ch2[] = \u001b[0m\u001b[1m\u001b[30m\u001b[41mstring.value\u001b[0m\u001b[1m\u001b[30m;\u001b[0m",
      "\u001b[1m\u001b[31mvalue has private access in java.lang.String\u001b[0m",
      ""
     ]
    }
   ],
   "source": [
    "public boolean equals(Object obj){\n",
    "    if(this == obj){ //优化，地址相等就一定相等\n",
    "        return true;\n",
    "    }\n",
    "    \n",
    "    if(obj instanceof String){\n",
    "        String string = (String) obj;\n",
    "        int n = value.length;\n",
    "        \n",
    "        if(n == string.value.length){\n",
    "            char ch1[] = value;\n",
    "            char ch2[] = string.value;\n",
    "            int i = 0;\n",
    "            while(n-- != 0){  //判断这两个字符串的数据是否相等\n",
    "                if(ch1[i] != ch2[i])\n",
    "                    return false;\n",
    "                i++;\n",
    "            }\n",
    "            return true;\n",
    "        }\n",
    "    }\n",
    "    return false;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "public int hashCode(){\n",
    "    int h = hash;\n",
    "    if(h == 0 && value.length > 0){\n",
    "        char val[] = value;\n",
    "        \n",
    "        for(int i = 0; i < value.lenght; i++){\n",
    "            h = 31 * h + value;\n",
    "        }\n",
    "    }\n",
    "    return h;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# toString方法\n",
    "## 原方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T15:12+0000",
     "start_time": "2020-08-25T15:12:49.194Z"
    }
   },
   "outputs": [
    {
     "ename": "CompilationException",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30mpublic String \u001b[0m\u001b[1m\u001b[30m\u001b[41mtoString\u001b[0m\u001b[1m\u001b[30m(){\u001b[0m",
      "\u001b[1m\u001b[31mJShell method names must not match Object methods: getClass wait hashCode equals notifyAll toString notify\u001b[0m",
      ""
     ]
    }
   ],
   "source": [
    "public String toString(){\n",
    "    return getClass.getName() + \"@\" + Integer.toHexString(hashCode());\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 重写方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-08-25T15:15+0000",
     "start_time": "2020-08-25T15:14:58.235Z"
    }
   },
   "outputs": [
    {
     "ename": "CompilationException",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1m\u001b[30m|   \u001b[1m\u001b[30mpublic String \u001b[0m\u001b[1m\u001b[30m\u001b[41mtoString\u001b[0m\u001b[1m\u001b[30m(){\u001b[0m",
      "\u001b[1m\u001b[31mJShell method names must not match Object methods: getClass wait hashCode equals notifyAll toString notify\u001b[0m",
      ""
     ]
    }
   ],
   "source": [
    "@Override\n",
    "public String toString(){\n",
    "    return \"Address{\" +\n",
    "    \"provinceNo=\" + proviceNo +\n",
    "    \", cityN=\" + cityNo +\n",
    "    \", streetNo=\" + streetNo +\n",
    "    '}';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# clone方法\n",
    "1. 拷贝的引用和原来对象的引用一般不相等\n",
    "2. 字节码文件对象一般相等(不强求)\n",
    "3. 拷贝对应和原对象调用equals一般相等(不强求)\n",
    "4. 通过super.clone调用\n",
    "5. 通常拷贝的对象与原对象是独立的\n",
    "6. 因此往往其**成员变量(如果是可变的引用)都需要拷贝一份出去**（实现完全独立）\n",
    "7. 该对象没有实现Cloneable接口会抛出异常\n",
    "8. 字段本身不克隆称为浅拷贝\n",
    "9. Object类本身没有实现Cloneable接口，在Object上调用clone方法一样会出现异常\n",
    "\n",
    "看了上面的注释我们可以总结以下的要点：\n",
    "- clone方法用于对象的克隆，一般想要克隆出的对象是**独立**的(与原有的对象是分开的)\n",
    "- 深拷贝指的是该对象的成员变量(如果是可变引用)都应该克隆一份，浅拷贝指的是成员变量没有被克隆一份\n",
    "比如一个类中的Date对象，为浅拷贝。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 讲得乱七八糟。。。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Java",
   "language": "java",
   "name": "java"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "Java",
   "pygments_lexer": "java",
   "version": "11.0.8+10-post-Ubuntu-0ubuntu120.04"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
